/*!
 * Huawei ThemeStudio Extensions
 * @version 1.0.1
 * @author Arnie
 * @copyright (c) 2022-present arnie.info All Rights Reserved.
 */

 function hwt_ext() {
    this.base_url = 'https://arnie.gitee.io/hwt-ext/';
    this.locale = localStorage.getItem('com.huawei.hwtdesigner.locale');

    this.plugins = {
        hwt_ext: {path: 'SELF', loaded: false},
        jscolor: {path: 'jscolor/jscolor.min.js', loaded: false},
    };

    // Vocabularies
    this.vocab = {
        'bg_color'      : {en: 'Background Color',  cn: '背景颜色'},
        'dial_outline'  : {en: 'Dial Outline',      cn: '表盘轮廓'},
        'option'        : {en: 'Option',            cn: '自定义选项'},
    };

    /** Get Vocabulary */
    this.get_vocab = ( key_name ) => {
        return this.vocab[key_name][this.locale];
    };

    /** Set view names */
    this.set_view_names = function(elem, ancestor) {
        const names = ancestor.getAttributeNames();
        for (let i = 0; i < names.length; i += 1) {
            if (names[i].indexOf('data-v') > -1) {
                elem.setAttribute(names[i], '');
            }
        }
    };

    /** Event agent */
    this.event_agent = function(selector, event, callback) {
        let times = 0;
        let timer = setInterval(()=>{
            let elem = document.querySelector(selector);
            if (elem || times > 99) {
                clearInterval(timer);
                if (elem) {
                    if (event === 'load') callback();
                    else elem.addEventListener(event, callback);
                } 
            }
            times += 1;
        },100); 
    };

    /** Listen to document changes */
    const observer = new MutationObserver( () => {
        // delete project
        if (location.hash.indexOf('/watchindex') > -1) {
            let projects = document.querySelectorAll('.right-main');
            for (let i = 0; i < projects.length; i += 1) {
                let btn_delete = projects[i].querySelector('button:last-child');
                btn_delete.onclick = () => {
                    let name = projects[i].querySelector('.name').innerText;
                    name = name.replace(/^\s+|\s+$/g).replaceAll(' ','_');
                    // confirm delete
                    setTimeout(() => {
                        let query = '.delete-dialog .btn:not(.cancle-btn)';
                        document.querySelector(query).onclick = ()=>{
                            localStorage.removeItem('layer.'+name);
                        }
                    },100); 
                }
            }
        }

    });
    observer.observe(document, {childList: true, subtree: true});
}

/** Initialize the plugin */
hwt_ext.prototype.init = function() {
    // initialize the interface
    const init_interface = ()=> {
        let route = window.location.hash;
        let is_watch_face = route.indexOf('/watch?') === 1;
        let is_phone_theme = route.indexOf('/menu/') === 1;

        if (is_watch_face) new watch_face;
        if (is_phone_theme) new phone_theme;
    };
    init_interface();

    // listen for hash changes
    const _history = function(type) { 
        const orig = history[type]; 
        const e = new Event(type); 
        return function() { 
            const rv = orig.apply(this, arguments); 
            e.arguments = arguments; window.dispatchEvent(e); 
            return rv; 
        }; 
    };
    history.pushState = _history('pushState');
    window.addEventListener('pushState', init_interface);

    // show success message
    if (! this.plugins.hwt_ext.loaded) {
        let message = 'The plugin is loaded and initialized successfully. ';
        let style = 'color:white;background:#006400;font-size:12px;padding:3px';
        console.log('%c'+message, style);

        this.plugins.jscolor.loaded = false;
    }
}


/** 
 * Watch face
 */
function watch_face() { 
    this._pub = new hwt_ext;

    // current project's name
    this.get_project_name = () => {
        let array = location.hash.match(/\?watchFaceName=(.*)/);
        return array[1].replaceAll('%20','_');
    };

    // watch face layers
    this._pub.event_agent('.watch-layer-select-wrapper', 'load', ()=>{
        this.init_layers();
    });

    // recorder
    this._pub.event_agent('.watch-record-icon', 'click', ()=>{
        if (! document.fullscreenElement)
            document.documentElement.requestFullscreen();
        setTimeout(()=>{
            this.init_recorder();
            document.getElementsByClassName('record-tool')[0].lastChild
                .addEventListener('click', ()=>{
                    document.exitFullscreen()
            });
        },100);
    });
}

/** Initialize recorder */
watch_face.prototype.init_recorder = function(){
    this.show_outline = false;

    const watch_img = this._pub.base_url + 'images/watch.png';
    const watch_img_size = 960;
    const dial_base_size = 466;
    const color_plugin = this._pub.base_url + this._pub.plugins.jscolor.path;
    
    this.record_tools = document.getElementsByClassName('record-tool')[0];
    this.record_area = document.getElementById('watch-record-arae');
    this.preview_wrap = document.getElementsByClassName('preview-record-warp')[0];
    this.dial_wrap = this.preview_wrap.children[1].firstChild;
    
    document.getElementsByClassName('record-tool-null')[0].style.display = 'none';

    const dial = this.dial_wrap.lastChild;
    let dial_width = dial.clientWidth;
    let dial_height = dial.clientHeight;

    if (dial_width !== dial_height) return;

    // button to show/hide the outline
    let btn_outline = document.createElement('button');
    btn_outline.className = 'btn';
    btn_outline.innerText = this._pub.get_vocab('dial_outline');
    this._pub.set_view_names(btn_outline, this.record_tools);
    btn_outline.addEventListener('click', () => { this.set_outline_visib() });
    this.record_tools.prepend(btn_outline);

    // button to set background color
    let btn_color = document.createElement('button');
    btn_color.className = 'btn';
    btn_color.innerText = this._pub.get_vocab('bg_color');
    this._pub.set_view_names(btn_color, this.record_tools);
    btn_color.setAttribute('id','btn-color-picker');

    // color picker
    const init_color_picker = ()=>{ 
        this.record_tools.prepend(btn_color);
        let bg_color = localStorage.getItem('video.bg_color') || '#000000';
        let option = {
            backgroundColor: '#585858', 
            value: bg_color, 
            previewElement: "#watch-record-arae",
            onChange: function() { 
                localStorage.setItem('video.bg_color', this.toString() )
            }
        };
        new jscolor(btn_color, option);
        this._pub.plugins.jscolor.loaded = true;
    }
    if (this._pub.plugins.jscolor.loaded) {
        init_color_picker();
    } else {
        let js_color = document.createElement('script');
        js_color.src = color_plugin; 
        document.getElementsByTagName('body')[0].appendChild(js_color);
        js_color.onload = init_color_picker;
    }

    // the outline of watch
    let watch_outline = document.createElement('div'),
        style = `position:absolute; left: 50%; top: 50%; opacity:0;
                width:${watch_img_size}px; height:${watch_img_size}px; 
                background-image: url(${watch_img}); background-size:cover;
                -webkit-transform:translate(-50%,-50%);`;
    watch_outline.setAttribute('style', style);
    watch_outline.style.zoom = dial_width / dial_base_size;
    
    let area_width = this.record_area.clientWidth;
    let scale = area_width / dial_width;
    this.dial_wrap.style.WebkitTransform = `scale( ${scale} )`;
    this.dial_wrap.style.zoom = '1';
    this.max_scale = scale;
    this.min_scale = area_width / (watch_img_size*watch_outline.style.zoom);

    this.dial_wrap.prepend(watch_outline);

    this.watch_outline = watch_outline;
}

/** Set visibility of the watch outline */
watch_face.prototype.set_outline_visib = function(e) {
    this.watch_outline.style.WebkitTransition = 'opacity 300ms linear';
    this.dial_wrap.style.WebkitTransition = 'transform 300ms linear';
    
    // show outline
    if (! this.show_outline) {
        this.watch_outline.style.opacity = 1;
        this.dial_wrap.style.WebkitTransform = `scale( ${this.min_scale} )`;
        this.show_outline = true;
    }

    // hide outline
    else {
        this.watch_outline.style.opacity = 0;
        this.dial_wrap.style.WebkitTransform = `scale( ${this.max_scale} )`;
        this.show_outline = false;
    }
}

/** Initialize layers */
watch_face.prototype.init_layers = function() {
    this.layers_initialized = false;
    const key_name = 'layer.'+this.get_project_name();

    let layers_json = localStorage.getItem(key_name);
    let layers_data = layers_json ? JSON.parse(layers_json) : null;
    setTimeout(() => {
        this.traverse_layers(true, layers_data);
    },100)

    const layers_area = document.querySelector('.layer-layer-area');
    const option = { attributes: true, childList: true, subtree: true };

    const observer = new MutationObserver( () => {
        if (this.layers_initialized) {
            let data = this.traverse_layers();
            let data_str = JSON.stringify(data);
            localStorage.setItem(key_name, data_str);
        }
    });
    observer.observe(layers_area, option);
}

/** Traverse the layer list */
watch_face.prototype.traverse_layers = function(init = false, data = null) {
    const unlock_code = 'NvbWJpbmVkLVNoYXBlIiBmaWxsPSIjMD';
    const visib_code = 'AgICAgICAgPHVzZSBpZD0iQ29tYmluZW';
    let layer_names = [];

    const traverse = (tree, items_data) => {
        let list_data = [];
        let hide_count = 0;
        let lock_count = 0;

        for (let i = 0; i < tree.childElementCount; i += 1) {
            let item = tree.children[i];
            let item_head = item.querySelector('[class^=layer]');
            if (! item_head) continue;

            // layer's name
            let name_selector = '.layer-name,.label-name,.widget-label-name';
            let name = item_head.querySelector(name_selector).innerText;
            name = name.replace(/^\s+|\s+$/g,'').replace(/\s{2,}/,' ');

            let btn_v = item_head.querySelector('.operate-start').firstChild;
            let btn_l = item_head.querySelector('.operate-item:last-child');
            let ico_t = item_head.querySelector('[class^=layer]');

            // layer/group status
            let hide = btn_v.firstChild.style.WebkitMask.indexOf(visib_code)>-1
                     ? 0 : 1;
            let lock = btn_l.firstChild.style.WebkitMask.indexOf(unlock_code)>-1
                     ? 0 : 1;
            let fold = ico_t.className.indexOf('down') > -1 
                     ? 0 : 1;
            let group = null;

            // when the custom options group has existed, skip it.
            let prefix =  this._pub.get_vocab('option');
            let skip = (name.indexOf(prefix)>-1 && layer_names.indexOf(name)>-1);

            if (! skip) {
                // layer subgroup
                let subitems = item.querySelector('[class^=layer][class$=area]');
                if (subitems) {
                    let data = items_data ? items_data[i].group : null;
                    let items = traverse(subitems, data); // recursion
                    group = items.list_data;

                    hide = items.hide_all ? 1 : 0;
                    lock = items.lock_all ? 1 : 0;
                }
                // simulate click event
                if (init && items_data) {
                    if (items_data[i].hide) {btn_v.click(); hide = 1} 
                    if (items_data[i].lock) {btn_l.click(); lock = 1}
                    if (items_data[i].fold && subitems) {ico_t.click();fold = 1}
                }
                layer_names.push(name);
            }

            if (hide) hide_count += 1;
            if (lock) lock_count += 1;

            list_data.push({ hide, lock, fold, group });
        }

        let lock_all = lock_count===list_data.length;
        let hide_all = hide_count===list_data.length;

        return {list_data, lock_all, hide_all};
    }

    const layers_area = document.querySelector('.layer-layer-area');
    let layers = traverse(layers_area, data);

    if (init) this.layers_initialized = true;

    return layers.list_data;
}


/** 
 * Phone theme
 */
function phone_theme() {
    let message = 'The extension for phone theme is not yet developed.';
    let style = 'color:white;background:#fb7e31;font-size:12px;padding:3px';
    console.log('%c'+message, style);
}
